home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / utils / graphic / viewers / general / amiga / he / iffstuff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-24  |  24.4 KB  |  978 lines

  1. /*
  2.     These are some IFF file handler routines...
  3. */
  4.  
  5. #define IFF_STUFF_C        1
  6.  
  7. #ifndef IFF_H
  8.     #include "iff.h"
  9. #endif
  10.  
  11. UBYTE iff_disk_buffer[4096];   /* a 4K disk buffer to speed I/O to file  */
  12. SHORT iff_buffer_size;            /*  these are not used at the moment     */
  13. SHORT iff_buffer_position;        /*  but I figure they may come in handy  */
  14. ULONG iff_file_position;        /*  sometime.  Only 8 bytes, no biggie   */
  15.  
  16.  
  17.  
  18.  
  19. /*
  20. $doc PullID
  21.     Function:    PullID(buffer)
  22.     
  23.     Inputs:        char *buffer;
  24.     
  25.     Synopsis:    PullID() is done here as an actual subroutine, although 
  26.                 it could just as easily be set up as a macro with a 
  27.                 #define.  All it does is takes a pointer to a text buffer 
  28.                 and yanks out the first four bytes and shifts them into a 
  29.                 ULONG, then returns it.
  30.                 
  31.     Returns:    returns a ULONG number.
  32.     
  33.     Bugs:        None
  34. $end
  35. */
  36.  
  37. ULONG PullID(what)
  38. UBYTE *what;
  39. {
  40.     return (ULONG)((ULONG)what[0]<<24 | (ULONG)what[1]<<16 | (ULONG)what[2]<<8 | (ULONG)what[3]);
  41. }
  42.  
  43.  
  44. /*
  45. $doc GetBMHD
  46.     Function:    GetBMHD(iff_file,header)
  47.     
  48.     Inputs:        FILE *iff_file;
  49.                 BitMapHeader *header;
  50.                 
  51.     Synopsis:    GetBMHD() searches the IFF file for a bitmap header and 
  52.                 reads the information into the BitMapHeader, one field at 
  53.                 a time.  This coud be made considerably faster and simpler 
  54.                 by doing a memcpy() from the disk buffer instead, but this 
  55.                 way makes it more clear what is in the BitMapHeader and 
  56.                 the relative positions within the file, so I'll leave it 
  57.                 like it is.
  58.     
  59.     Returns:    TRUE on error, FALSE on success.
  60.     
  61.     Bugs:        None known.
  62.     
  63.     See Also:    iff.h (contains the BitMapHeader structure).
  64. $end
  65. */
  66.     
  67. BOOL GetBMHD(ifffile,header)
  68. FILE *ifffile;
  69. BitMapHeader *header;
  70. {
  71.     Chunk bmhdchunk;
  72.     BOOL error;
  73.                                         /* first find the chunk */
  74.     error=FindChunk(ifffile,MakeID('B','M','H','D'),&bmhdchunk);
  75.     if(error)
  76.         return TRUE;                    /* read the data into header */
  77.     header->w = ((UWORD)(bmhdchunk.ckdata[0]) << 8) | (bmhdchunk.ckdata[1]);
  78.     header->h = ((UWORD)(bmhdchunk.ckdata[2]) << 8) | (bmhdchunk.ckdata[3]);
  79.     header->x = ((WORD)(bmhdchunk.ckdata[4]) << 8) | (bmhdchunk.ckdata[5]);
  80.     header->y = ((WORD)(bmhdchunk.ckdata[6]) << 8) | (bmhdchunk.ckdata[7]);
  81.     header->nplanes = bmhdchunk.ckdata[8];
  82.     header->masking = bmhdchunk.ckdata[9];
  83.     header->compression = bmhdchunk.ckdata[10];
  84.     header->pad1 = 0;                    /* set to 0 and skip over a byte */
  85.     header->TransparentColor = (UWORD)(bmhdchunk.ckdata[12] << 8) | (bmhdchunk.ckdata[13]);
  86.     header->xAspect = bmhdchunk.ckdata[14];
  87.     header->yAspect = bmhdchunk.ckdata[15];
  88.     header->pageWidth = ((WORD)(bmhdchunk.ckdata[16]) << 8) | (bmhdchunk.ckdata[17]);
  89.     header->pageHeight = ((WORD)(bmhdchunk.ckdata[18]) << 8) | (bmhdchunk.ckdata[19]);
  90.     FreeMem(bmhdchunk.ckdata,bmhdchunk.cksize);        /* free memory */
  91.     return FALSE;
  92. }
  93.  
  94. /* 
  95. $doc GetViewModes
  96.     Function:    GetViewModes(newscreen, iff_file)
  97.     
  98.     Inputs:        struct NewScreen *newscreen;
  99.                 FILE *iff_file;
  100.                 
  101.     Synopsis:    GetViewModes() looks for a CAMG chunk in the IFF file.
  102.                 If it finds one, it stores the ViewModes word into the 
  103.                 NewScreen structure.  If there isn't, it sets up the 
  104.                 minimal assumptions necessary to open the screen properly 
  105.                 (i.e. lace or not and hires or not).
  106.                 
  107.     Returns:    TRUE on error, FALSE on success.
  108.     
  109.     Bugs:        Makes no assumptions about the extended screen modes found
  110.                 under WorkBench 2.0, so that this will work on 1.3 machines.
  111.                 Most fancy-screen-mode pictures should probably have a CAMG
  112.                 chunk in them anyway.
  113. $end
  114. */
  115.  
  116. BOOL GetViewModes(newscreen,ifffile)
  117. struct NewScreen *newscreen;
  118. FILE *ifffile;
  119. {
  120.     BOOL error = FALSE;
  121.     Chunk camgchunk;
  122.     
  123.     error = FindChunk(ifffile,MakeID('C','A','M','G'),&camgchunk);
  124.     if(!error)
  125.         {
  126.             newscreen->ViewModes = PullID(camgchunk.ckdata) & CAMGMASK;
  127.             FreeMem(camgchunk.ckdata,camgchunk.cksize);
  128.         }
  129.     if(newscreen->Width > 384)            /* if no CAMG chunk, make it up */
  130.         newscreen->ViewModes |= HIRES;    /* if there was one, this won't */
  131.     if(newscreen->Height > 200)            /* hurt anything to double-check */
  132.         newscreen->ViewModes |= LACE;
  133.     return FALSE;    
  134. }
  135.  
  136. /*
  137. $doc FindChunk
  138.     Function:    FindChunk(iff_file,chunktype,chunk)
  139.     
  140.     Inputs:        FILE *iff_file;
  141.                 ULONG chunktype;
  142.                 Chunk chunk;
  143.                 
  144.     Synopsis:    FindChunk searches an IFF file for a chunk of type 
  145.                 chunktype.  It makes use of the iff_disk_buffer for 
  146.                 speedier I/O.  The buffer could be diddled with a little 
  147.                 to improve speed, but you might wind up with overkill on 
  148.                 the reads (probably already a lot of that at 4K).  If it 
  149.                 finds the chunk, it allocates memory for the chunk body 
  150.                 UNLESS it is a BODY type chunk.  It then reads the data 
  151.                 into the chunkdata section and returns.  It is up to the 
  152.                 caller to free the allocated memory.  If it is looking for
  153.                 a BODY type chunk, rather than allocate memory for the
  154.                 body, it leaves this part up to the caller (useful for 
  155.                 on-the-fly decompression), and instead positions the IFF 
  156.                 file pointer so that it points to the start of the BODY 
  157.                 chunk data.
  158.                 
  159.     Returns:    TRUE on error, FALSE on success.
  160.     
  161.     Bugs:        None known.
  162. $end
  163. */
  164.  
  165. BOOL FindChunk(ifffile,chunktype,chunk)
  166. FILE *ifffile;
  167. ULONG chunktype;
  168. Chunk *chunk;
  169. {
  170.     SHORT temppos;
  171.     BOOL foundchunk= FALSE;
  172.     ULONG bytes_read=0,seek_spot=0;
  173.     SHORT buffer_size=0;
  174.     
  175.     rewind(ifffile);                /* start at top of file  */
  176.     buffer_size = fread(iff_disk_buffer,1,4096,ifffile);    /* fill buffer */
  177.     while(TRUE)        /* search whole file for chunk */
  178.         {
  179.             for(temppos=0;temppos<buffer_size;temppos++)    /* scan buffer */
  180.                 if(PullID(&iff_disk_buffer[temppos]) == chunktype)
  181.                     {
  182.                         foundchunk = TRUE;    /* found chunk type ? */
  183.                         break;
  184.                     }
  185.             if((foundchunk) || feof(ifffile))    /* done ? */
  186.                 break;
  187.             buffer_size = fread(iff_disk_buffer,1,4096,ifffile);
  188.             bytes_read += buffer_size;        /* how far are we into file? */
  189.         };    
  190.     seek_spot = bytes_read + temppos + 8;    /* for a BODY chunk */
  191.     if(foundchunk)    
  192.         {
  193.             chunk->ckID = PullID(&iff_disk_buffer[temppos]);
  194.             chunk->cksize = PullID(&iff_disk_buffer[temppos+4]);
  195.             if(chunk->ckID == MakeID('B','O','D','Y'))
  196.                 {
  197.                     chunk->ckdata = NULL;        /* fix file pointer */
  198.                     fseek(ifffile,seek_spot,SEEK_SET);
  199.                     return FALSE;                /* I'm outta here... */
  200.                 }
  201.             chunk->ckdata = (UBYTE *)AllocMem(chunk->cksize,MEMF_CLEAR);
  202.             if(chunk->ckdata == NULL)    /* not a BODY chunk at this point */
  203.                 {
  204.                     printf("\nNo memory for chunk!!\n");
  205.                     return TRUE;
  206.                 }
  207.             temppos += 8;    /* read the data into the chunkdata section */
  208.             for(bytes_read=0;bytes_read<chunk->cksize;bytes_read++)
  209.                 chunk->ckdata[bytes_read] = iff_disk_buffer[temppos++];
  210.         }    
  211.     else
  212.         return TRUE;    /* hey, somethin' ain't right */
  213.     return FALSE;        /* everything's fine */
  214. }
  215.  
  216. /*
  217. $doc GetColorMap
  218.     Function:    GetColorMap(iff_file,colortable)
  219.     
  220.     Inputs:        FILE *iff_file;
  221.                 UWORD *colortable;
  222.                 
  223.     Synopsis:    GetColorMap scans an IFF file for a colormap, loading it 
  224.                 into the colortable array given.
  225.                 
  226.     Returns:    A SHORT describing the number of colors in the table.
  227.     
  228.     Bugs:        The caller should be sure that the color table is large
  229.                 enough to hold the colormap.  This routine will be perfectly
  230.                 happy to cram a 32-color colormap into an array that only
  231.                 holds 16, which would lead to highly unpredictable 
  232.                 behavior and undesired results.
  233. $end
  234. */
  235.  
  236. SHORT GetColorMap(ifffile,colortable)
  237. FILE *ifffile;
  238. UWORD *colortable;
  239. {
  240.     Chunk cmapchunk;
  241.     SHORT count=0;
  242.     BOOL error = FALSE;
  243.     UWORD red,green,blue;
  244.  
  245.     error = FindChunk(ifffile,MakeID('C','M','A','P'),&cmapchunk);
  246.     if(!error)                                /* found colormap? */
  247.         {                                    /* make RGB4's out of it */
  248.             for(;count<cmapchunk.cksize/3;count++)
  249.                 {
  250.                     red = cmapchunk.ckdata[(count*3)] >> 4;        /* use high order 4 bits */
  251.                     green = cmapchunk.ckdata[(count*3)+1] >> 4;
  252.                     blue = cmapchunk.ckdata[(count*3)+2] >> 4;
  253.                     colortable[count]  = blue;
  254.                     colortable[count] |= green << 4;
  255.                     colortable[count] |= red << 8;
  256.                 }
  257.             FreeMem(cmapchunk.ckdata,cmapchunk.cksize);
  258.         }
  259.     return (count);
  260. }
  261.  
  262.  
  263. /*
  264. $doc ReadPic
  265.     Function:    ReadPic(bitmap,iff_file,header)
  266.     
  267.     Inputs:        struct BitMap *bitmap;
  268.                 FILE *iff_file;
  269.                 BitMapHeader *header;
  270.                 
  271.     Synopsis:    ReadPic() is the picture reader.  It takes a pointer to 
  272.                 a bitmap, a pointer to a file which need not be at any 
  273.                 particular position, (it will find the data with 
  274.                 FindChunk()), and a pointer to a BitMapHeader describing 
  275.                 the picture being read.  It doesn't matter whether the 
  276.                 picture is on or off screen or whether it is not the same 
  277.                 size as the bitmap.  If it is too small, it is read anyway.
  278.                 If it is too large, it is clipped at the BitMap boundaries.
  279.                 Compressed and masked images are handled correctly.
  280.                 
  281.     Returns:    TRUE on error, FALSE on success.
  282.     
  283.     Bugs:        Doesn't seem to care for Deluxe Paint images with stencils
  284.                 attached to them.  (I have yet to see anything that handles
  285.                 those things right except Deluxe Paint.)  All other images
  286.                 work correctly, including brushes.
  287. $end
  288. */
  289.  
  290. BOOL ReadPic(bitmap,ifffile,header)
  291. struct BitMap *bitmap;
  292. FILE *ifffile;
  293. BitMapHeader *header;
  294. {
  295.     BOOL error = FALSE;
  296.     BOOL mask = FALSE;
  297.     BOOL compress = FALSE;
  298.     Chunk bodychunk;
  299.     SHORT scanline,plane,count,needed,read;
  300.     BYTE data,run;
  301.     UBYTE bit_bucket[255];
  302.     UBYTE *dest;
  303.     
  304.     if(header->masking == mskHasMask)
  305.         mask = TRUE;                    /* got a mask on it ?*/
  306.     if(header->compression == cmpByteRun1)
  307.         compress = TRUE;                /* compressed via ByteRun1? */
  308.     needed = header->w/8;                /* how many BYTES do we need? */
  309.     if(header->w%8)                        /* if odd number of pixels, */
  310.         needed++;                        /* adjust number of bytes needed */
  311.     if(needed%2)        /*    old word align */
  312.         needed++;                           
  313.     if(needed<2)
  314.         needed = 2;            /* for tiny brushes  */
  315.     error = FindChunk(ifffile,MakeID('B','O','D','Y'),&bodychunk);
  316.     if(error)
  317.         return TRUE;                    /* YIKES!  No Body! */
  318.     for(scanline=0;scanline<header->h;scanline++)    /* lines first */
  319.         for(plane=0;plane<header->nplanes;plane++)    /* then planes */
  320.             {
  321.                 if(mask & scanline%2)            /* ignore mask */
  322.                     dest = bit_bucket;            /* toss mask planes */
  323.                 else                        /* figure scanline in bitmap */
  324.                     dest = bitmap->Planes[plane]+(scanline*bitmap->BytesPerRow);
  325.                 if(!compress)                /* not too likely, but easy */
  326.                     for(count=0;count<needed;count++)
  327.                         *dest++ = fgetc(ifffile);
  328.                 else                        /* image is compressed */
  329.                     {
  330.                         count=0;            /* count is bytes decompressed */
  331.                         while(count<needed)    
  332.                             {
  333.                                 run = fgetc(ifffile);    /* size of run */
  334.                                 if(run>=0)                /* literal run */
  335.                                     {
  336.                                         count += run+1;
  337.                                         for(read=0;read<=run;read++)
  338.                                             *dest++ = fgetc(ifffile);
  339.                                     }
  340.                                 else if (run != 128)    /* repeat run */
  341.                                     {
  342.                                         run = run*(-1);
  343.                                         count += run+1;
  344.                                         data = fgetc(ifffile);
  345.                                         for(read=0;read<=run;read++)
  346.                                             *dest++ = data;
  347.                                     }
  348.                             }
  349.                     }
  350.         }
  351.     return FALSE;
  352. }
  353.  
  354.  
  355. /*
  356. $doc LoadPicture
  357.     Function:    LoadPicture(iff_file,bitmap)
  358.     
  359.     Inputs:        FILE *iff_file;
  360.                 struct BitMap *bitmap;
  361.                 
  362.     Synopsis:    Simply loads the requested IFF picture into the bitmap.
  363.                 (Note that the caller must do their own colormap setup and
  364.                 screen setup.  This is about the simplest routine I can
  365.                 make for loading pictures and still keep it general enough
  366.                 for off-screen loads and such.)
  367.     
  368.     Returns:    TRUE on error, FALSE on success.
  369.     
  370.     Bugs:        None known.
  371.     
  372.     See Also:    ReadPic()
  373. $end
  374. */    
  375.     
  376. BOOL LoadPicture(file,bitmap)
  377. FILE *file;
  378. struct BitMap *bitmap;
  379. {
  380.     BOOL error;
  381.     BitMapHeader bmhd;
  382.     
  383.     if(error = GetBMHD(file,&bmhd))
  384.         return TRUE;
  385.     if(error = ReadPic(bitmap,file,&bmhd))     /* decode it */
  386.         return TRUE;
  387.     return FALSE;
  388. }
  389.  
  390.  
  391.  
  392. /* 
  393.    **********************************************************************
  394.    This part is for sounds.  Routines are here for loading, playing,
  395.    and freeing up sounds.  This makes adding digitized sounds to a program
  396.    ridiculously easy.
  397.    **********************************************************************
  398. */
  399.  
  400.  
  401. /*
  402. $doc LoadSound
  403.     Function:    LoadSound(sound_name)
  404.     
  405.     Inputs:        char *sound_name;
  406.     
  407.     Synopsis:    LoadSound() takes a pointer to a filename which contains
  408.                 an 8SVX sampled sound.  It loads this file into memory 
  409.                 into an ASound structure.
  410.                 
  411.     Returns:     Pointer to an ASound structure or NULL on failure.
  412.     
  413.     Bugs:        None known.
  414.     
  415.     See Also:    iff.h (structure definition for ASound).
  416. $end
  417. */
  418.  
  419. struct ASound *LoadSound(name)
  420. char *name;
  421. {
  422.     FILE *file;
  423.     Chunk bodychunk;
  424.     BOOL error;
  425.     BYTE *sounddata = NULL;
  426.     ULONG length;
  427.     struct ASound *sound;
  428.     
  429.     if(!(file = fopen(name,"rb")))
  430.         return NULL;
  431.     sound = (struct ASound *)AllocMem(sizeof(struct ASound),MEMF_CLEAR);
  432.     if(!sound)
  433.         {
  434.             fclose(file);
  435.             return NULL;
  436.         }
  437.     GetVoiceHeader(file,&sound->vhead);
  438.     error = FindChunk(file,ID_BODY,&bodychunk);
  439.     if(error)
  440.         {
  441.             FreeMem(sound,sizeof(struct ASound));
  442.             fclose(file);
  443.             return NULL;
  444.         }
  445.     length = sound->vhead.oneShotHiSamples;
  446.     if(!length)
  447.         length = sound->vhead.repeatHiSamples;
  448.     sounddata = (BYTE *)AllocMem(length,MEMF_CLEAR|MEMF_CHIP);
  449.     if(!sounddata)
  450.         {
  451.             FreeMem(sound,sizeof(struct ASound));
  452.             fclose(file);
  453.             return NULL;
  454.         }
  455.     fread(sounddata,bodychunk.cksize,1,file);
  456.     sound->datasize = length;
  457.     sound->data = sounddata;
  458.     return sound;
  459. }
  460.  
  461.  
  462. /*
  463. $doc GetVoiceHeader
  464.     Function:    GetVoiceHeader(sound_file,voice_header)
  465.     
  466.     Inputs:        FILE *sound_file;
  467.                 Voice8Header *voice_header;
  468.                 
  469.     Synopsis:    Reads an IFF 8SVX file and gets the voice header 
  470.                 information, storing it into the Voice8Header structure 
  471.                 passed to it.  
  472.                 
  473.     Returns:    It returns TRUE on success, FALSE on failure.
  474.     
  475.     Bugs:        None known.
  476. $end
  477. */
  478.  
  479. BOOL GetVoiceHeader(file,vhead)
  480. FILE *file;
  481. Voice8Header *vhead;
  482. {
  483.     Chunk v8chunk;
  484.     BOOL error;
  485.     
  486.     error = FindChunk(file,ID_VHDR,&v8chunk);
  487.     if(error)
  488.         return FALSE;
  489.     memcpy(vhead,v8chunk.ckdata,v8chunk.cksize);
  490.     FreeMem(v8chunk.ckdata,v8chunk.cksize);
  491.     return TRUE;
  492. }
  493.  
  494.  
  495. /*
  496. $doc OpenAudio
  497.     Function:    OpenAudio(void)
  498.     
  499.     Inputs:        none
  500.     
  501.     Synopsis:    Here's a function that opens the audio device and 
  502.                 allocates all four channels so that nobody will steal them
  503.                 away from you.  It also    sets up the IOAudio requests for 
  504.                 all four channels to allow you to play several samples 
  505.                 simultaneously, if you so desire.
  506.             
  507.     Returns:    TRUE on success, FALSE on failure.
  508.     
  509.     Bugs:        None known.
  510. $end
  511. */
  512.  
  513. BOOL OpenAudio()
  514. {
  515.     int count;
  516.     ULONG error = FALSE;
  517.     
  518.     AudioPort = (struct MsgPort *)CreatePort(0,0);
  519.     if(!AudioPort)
  520.         return FALSE;
  521.     for(count=0;count<5;count++)
  522.         {
  523.             if(!(channels[count] = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_CHIP|MEMF_CLEAR)))
  524.                 error = TRUE;
  525.             channels[count]->ioa_Request.io_Message.mn_ReplyPort = AudioPort;
  526.  
  527.         }
  528.     if(error)
  529.         {
  530.             for(count=0;count<5;count++)
  531.                 {
  532.                     if(channels[count])
  533.                         FreeMem(channels[count],sizeof(struct IOAudio));
  534.                     channels[count] = NULL;
  535.                 }
  536.             if(AudioPort)
  537.                 DeletePort(AudioPort);
  538.             AudioPort = NULL;
  539.             return FALSE;
  540.         }
  541.     channels[CONTROL]->ioa_Length = 0;        /* set to just open device */
  542.     error = OpenDevice("audio.device",0L,(struct IORequest *)channels[CONTROL],0L);
  543.     if(error)        /* couldn't get the device! */
  544.         {
  545.             for(count=0;count<5;count++)
  546.                 {
  547.                     if(channels[count])
  548.                         FreeMem(channels[count],sizeof(struct IOAudio));
  549.                     channels[count] = NULL;
  550.                 }
  551.             if(AudioPort)
  552.                 DeletePort(AudioPort);
  553.             AudioPort = NULL;
  554.             return FALSE;
  555.         }
  556.     for(count=0;count<4;count++)        /* allocate all four channels */
  557.         {
  558.             channels[count]->ioa_Request.io_Message.mn_Node.ln_Pri = 127;  /* No stealing! */
  559.             channels[count]->ioa_Data = &alloc_all_channels[count];
  560.             channels[count]->ioa_Request.io_Device = channels[CONTROL]->ioa_Request.io_Device;
  561.             channels[count]->ioa_Length = 1;
  562.             channels[count]->ioa_Request.io_Command = ADCMD_ALLOCATE;
  563.             channels[count]->ioa_Request.io_Flags = ADIOF_NOWAIT | IOF_QUICK;
  564.             BeginIO(channels[count]);
  565.             error = WaitIO(channels[count]);
  566.             if(!(channels[count]->ioa_Request.io_Flags & IOF_QUICK))
  567.                 GetMsg(AudioPort);
  568.             if(error)
  569.                 break;
  570.             if(channels[count]->ioa_Request.io_Unit != (struct Unit *)alloc_all_channels[count])
  571.                 {
  572.                     error = TRUE;
  573.                     break;
  574.                 }
  575.         }
  576.     if(error)    /* couldn't get all four channels */
  577.         {
  578.             for(count=0;count<5;count++)
  579.                 {
  580.                     if(channels[count])
  581.                         FreeMem(channels[count],sizeof(struct IOAudio));
  582.                     channels[count] = NULL;
  583.                 }
  584.             if(AudioPort)
  585.                 DeletePort(AudioPort);
  586.             AudioPort = NULL;
  587.             CloseDevice(channels[CONTROL]);
  588.             return FALSE;
  589.         }
  590.     return TRUE;
  591. }        
  592.  
  593.  
  594.  
  595. /*
  596. $doc PlaySound
  597.     Function:    PlaySound(sound,loops,volume,channel)
  598.     
  599.     Inputs:        struct ASound *sound;
  600.                 SHORT loops;
  601.                 UWORD volume;
  602.                 SHORT channel;
  603.                 
  604.     Synopsis:    PlaySound takes a pointer to an ASound structure (such as 
  605.                 that returned by LoadSound()), plays it loops number of 
  606.                 times at the requested volume on the specified channel.
  607.                 It does NOT wait for the audio device to return.
  608.                 
  609.     Returns:    none
  610.     
  611.     Bugs:        None known.
  612. $end
  613. */
  614.  
  615. void PlaySound(sound, loops, vol, channel)
  616. struct ASound *sound;
  617. SHORT loops;
  618. UWORD vol;
  619. SHORT channel;
  620. {
  621.     ULONG speed;
  622.     ULONG length;
  623.     
  624.     if((channel<0) || (channel>3))
  625.         return;
  626.     length = sound->vhead.oneShotHiSamples;
  627.     if(!length)
  628.         length = sound->vhead.repeatHiSamples;
  629.     speed = NTSC_CLOCK/sound->vhead.samplesPerSec;
  630.     channels[channel]->ioa_Request.io_Command = CMD_WRITE;
  631.     channels[channel]->ioa_Request.io_Flags = ADIOF_PERVOL|ADIOF_NOWAIT|IOF_QUICK;
  632.     channels[channel]->ioa_Volume = vol;
  633.     channels[channel]->ioa_Period = (UWORD)speed;    
  634.     channels[channel]->ioa_Cycles = loops;
  635.     channels[channel]->ioa_Data = sound->data;
  636.     channels[channel]->ioa_Length = sound->datasize;
  637.     whichsound[channel] = sound;
  638.     BeginIO((struct IORequest *)channels[channel]);
  639.     return;
  640. }
  641.  
  642.  
  643. /*
  644. $doc FreeSound
  645.     Function:    FreeSound(sound)
  646.     
  647.     Inputs:        struct ASound *sound;
  648.     
  649.     Synopsis:    FreeSound() takes a pointer to an ASound structure and 
  650.                 frees up all memory associated with it.  Before memory is 
  651.                 freed, the active sounds are checked and if a channel is 
  652.                 currently playing that sound, a call is made to 
  653.                 AbortChannel().
  654.                 
  655.     Returns:    None.
  656.     
  657.     Bugs:        None known.
  658. $end
  659. */
  660.  
  661. void FreeSound(sound)
  662. struct ASound *sound;
  663. {
  664.     int count;
  665.     
  666.     if(!sound)            /* don't hand me no NULLs, dudes...   */
  667.         return;
  668.     for(count=0;count<4;count++)
  669.         if(whichsound[count] == sound)
  670.             {
  671.                 AbortChannel(count);
  672.                 whichsound[count] = NULL;
  673.             }
  674.     if(sound->data)
  675.         FreeMem(sound->data,sound->datasize);
  676.     FreeMem(sound,sizeof (struct ASound));
  677.     return;
  678. }
  679.  
  680.  
  681. /*
  682. $doc CloseAudio
  683.     Function:    CloseAudio(void)
  684.     
  685.     Inputs:        None.
  686.     
  687.     Synopsis:    CloseAudio() just closes down the audio device so other 
  688.                 programs can have at it.  It also frees up all the IOAudio
  689.                 requests.  It also makes sure the sounds are all aborted 
  690.                 before closing it all down.
  691.     
  692.     Returns:    None.
  693.     
  694.     Bugs:        None known.
  695. $end
  696. */
  697.  
  698. void CloseAudio()
  699. {
  700.     int count;
  701.     
  702.     for(count=0;count<4;count++)
  703.         {
  704.             if(whichsound[count])
  705.                 AbortChannel(count);
  706.             CloseDevice(channels[count]);
  707.             if(channels[count])
  708.                 FreeMem(channels[count],sizeof(struct IOAudio));
  709.             whichsound[count] = NULL;
  710.             channels[count]  = NULL;
  711.         }
  712.     CloseDevice(channels[CONTROL]); 
  713.     if(AudioPort)
  714.         DeletePort(AudioPort);
  715.     AudioPort = NULL;
  716.     if(channels[CONTROL])
  717.         FreeMem(channels[count],sizeof(struct IOAudio));
  718.     channels[CONTROL] = NULL;
  719.     return;
  720. }
  721.  
  722.  
  723. /*
  724. $doc WaitSounds
  725.     Function:    WaitSounds(sound1,sound2,sound3,sound4)
  726.     
  727.     Inputs:        struct ASound *sound1, *sound2, *sound3, *sound4;
  728.     
  729.     Synopsis:    WaitSounds() takes pointers to 4 sounds, any or all of 
  730.                 which can be NULL, and waits on the combination to finish
  731.                 playing before returning.  Actually it just converts the 
  732.                 sound pointers to a channel mask and makes a call to 
  733.                 WaitChannels(), which actually sits there and waits.
  734.     
  735.     Returns:    None.
  736.     
  737.     Bugs:        None known.
  738.     
  739.     See Also:    WaitChannels().
  740. $end
  741. */
  742.  
  743. void WaitSounds(sound1, sound2, sound3, sound4)
  744. struct ASound *sound1, *sound2, *sound3, *sound4;
  745. {
  746.     SHORT channelmask = 0;
  747.     int count;
  748.     
  749.     for(count=0;count<4;count++)
  750.         {
  751.             if((whichsound[count] == sound1) && (sound1))
  752.                 channelmask |= 1 << count;
  753.             if((whichsound[count] == sound2) && (sound2))
  754.                 channelmask |= 1 << count;
  755.             if((whichsound[count] == sound3) && (sound3))
  756.                 channelmask |= 1 << count;
  757.             if((whichsound[count] == sound4) && (sound4))
  758.                 channelmask |= 1 << count;
  759.             if(channelmask & (1 << count))
  760.                 whichsound[count] = NULL;
  761.         }
  762.     if(!channelmask)    /* no channels to wait on */
  763.         return;
  764.     WaitChannels(channelmask);
  765.     return;
  766. }
  767.  
  768. /*
  769. $doc
  770.  
  771.     Function:    WaitChannels(mask)
  772.     
  773.     Inputs:        SHORT mask;
  774.                     
  775.     Synopsis:    Simply waits for specified sound channels to finish
  776.                 playing.  Sound channels are specified as a bitmask in
  777.                 bits 0-3 where a bit set means to wait on that
  778.                 channel.  Waits are done in serial fashion.  This is
  779.                 fine since we want all the channels specified to finish
  780.                 before we return.  If we wait on one sound and another
  781.                 one finishes first, it will be caught on a sebsequent
  782.                 pass back through the wait loop.
  783.  
  784.     Returns:    None.
  785.  
  786.     Bugs:        None known.
  787. $end
  788. */
  789.  
  790. void WaitChannels(mask)
  791. SHORT mask;
  792. {
  793.     int count;
  794.     
  795.     for(count=0;count<4;count++)
  796.         if(mask & (1 << count))
  797.             {
  798.                 if(CheckIO(channels[count]))    /* if sound is done */
  799.                     {                            /* mark it that way */
  800.                         while(GetMsg(AudioPort));
  801.                         whichsound[count] = NULL;
  802.                     }
  803.                 else                            /* if not done, wait */
  804.                     {                            /* for it to finish  */
  805.                         WaitIO(channels[count]);
  806.                         count--;                /* and repeat this pass */
  807.                     }
  808.             }
  809.     return;
  810. }
  811.  
  812.  
  813. /*
  814. $doc AbortSound
  815.     Function:    AbortSound(sound)
  816.     
  817.     Inputs:        struct ASound *sound;
  818.     
  819.     Synopsis:    AbortSound() aborts playback of a sound, if it is 
  820.                 currently playing, by figuring out which channel it is 
  821.                 playing on, then doing a call to AbortChannel for that 
  822.                 channel.
  823.                 
  824.     Returns:    None
  825.     
  826.     Bugs:        None known.
  827.     
  828.     See Also:    iff.h (For whichsound[] array that tracks where sounds are 
  829.                 currently playing.)
  830.                 AbortChannel().
  831. $end
  832. */
  833.  
  834. void AbortSound(sound)
  835. struct ASound *sound;
  836. {
  837.     int count;
  838.     
  839.     if(!sound)
  840.         return;
  841.     for(count=0;count<4;count++)
  842.         if(whichsound[count] == sound)
  843.             AbortChannel(count);
  844.     return;
  845. }
  846.  
  847. /*
  848. $doc AbortChannel
  849.     Function:    AbortChannel(channel)
  850.     
  851.     Inputs:        int channel;
  852.     
  853.     Synopsis:    Tells the audio device to finish the sound playing on the
  854.                 indicated channel (according to the whichsound[] array).
  855.                 Also marks the sound as done in the whichsound[] array.
  856.                 
  857.     Returns:    None
  858.     
  859.     Bugs:        None known.
  860. $end
  861. */
  862.  
  863. void AbortChannel(channel)        /* stops a sound and marks it as done */
  864. int channel;
  865. {
  866.     channels[CONTROL]->ioa_Request.io_Unit = channels[channel]->ioa_Request.io_Unit;
  867.     channels[CONTROL]->ioa_AllocKey = channels[channel]->ioa_AllocKey;
  868.     channels[CONTROL]->ioa_Request.io_Command = ADCMD_FINISH;
  869.     channels[CONTROL]->ioa_Request.io_Flags = ADIOF_NOWAIT|IOF_QUICK;
  870.     channels[CONTROL]->ioa_Length = 0;
  871.     BeginIO(channels[CONTROL]);
  872.     WaitIO(channels[CONTROL]);
  873.     if(!(channels[CONTROL]->ioa_Request.io_Flags & IOF_QUICK))
  874.         GetMsg(AudioPort);
  875.     whichsound[channel] = NULL;
  876.     return;
  877. }
  878.  
  879.  
  880. /*
  881. $doc StartAudio
  882.     Function:    StartAudio(void)
  883.     
  884.     Inputs:        None
  885.     
  886.     Synopsis:    Sends a command to the audio device to start playing.  If 
  887.                 there are any sounds already queued up (by PlaySound() or
  888.                 whatever), they will begin immediately on all channels.
  889.     
  890.     Returns:    None
  891.     
  892.     Bugs:        None known.
  893.     
  894.     See Also:    StopAudio(), LoadSound().
  895. $end
  896. */
  897.  
  898. void StartAudio()
  899. {
  900.     int count;
  901.  
  902.     for(count=0;count<4;count++)
  903.         {    
  904.             channels[4]->ioa_Request.io_Device = channels[count]->ioa_Request.io_Device;
  905.             channels[4]->ioa_AllocKey = channels[count]->ioa_AllocKey;
  906.             channels[4]->ioa_Request.io_Unit = channels[count]->ioa_Request.io_Unit;
  907.             channels[4]->ioa_Length = 0;
  908.             channels[4]->ioa_Request.io_Command = CMD_START;
  909.             BeginIO(channels[4]);
  910.             WaitPort(AudioPort);        /* global reply port here */
  911.             GetMsg(AudioPort);
  912.         }
  913.     return;
  914. }    
  915.  
  916. /*
  917. $doc StopAudio
  918.     Function:    StopAudio(void)
  919.     
  920.     Inputs:        None.
  921.     
  922.     Synopsis:    Sends a message to the audio device to stop playing.  It 
  923.                 will not clear any sounds that are already queued up, so
  924.                 this could be more accurately thought of as a pause in the
  925.                 output.  Sound will resume when you call StartAudio().
  926.                 
  927.     Returns:    None.
  928.     
  929.     Bugs:        None known.
  930.     
  931.     See Also:    StartAudio().
  932. $end
  933. */
  934.  
  935. void StopAudio()
  936. {
  937.     int count;
  938.  
  939.     for(count=0;count<4;count++)
  940.         {    
  941.             channels[4]->ioa_Request.io_Device = channels[count]->ioa_Request.io_Device;
  942.             channels[4]->ioa_AllocKey = channels[count]->ioa_AllocKey;
  943.             channels[4]->ioa_Request.io_Unit = channels[count]->ioa_Request.io_Unit;
  944.             channels[4]->ioa_Length = 0;
  945.             channels[4]->ioa_Request.io_Command = CMD_STOP;
  946.             BeginIO(channels[4]);
  947.             WaitPort(AudioPort);
  948.             GetMsg(AudioPort);
  949.         }
  950.     return;
  951. }    
  952.  
  953. /*
  954. $doc AbortAllSounds
  955.     Function:    AbortAllSounds(void)
  956.     
  957.     Inputs:        None.
  958.     
  959.     Synopsis:    Simply aborts all four audio channels and marks them all as
  960.                 done.
  961.     
  962.     Returns:    None.
  963.     
  964.     Bugs:        None known.
  965.     
  966.     See Also:    AbortChannel().
  967. $end
  968. */
  969.     
  970. void AbortAllSounds()
  971. {
  972.     AbortChannel(LEFTA);
  973.     AbortChannel(LEFTB);
  974.     AbortChannel(RIGHTA);
  975.     AbortChannel(RIGHTB);
  976.     return;
  977. }
  978.